using System;
using System.Collections.Generic;

namespace Impact.Controllers
{

    /// <summary>
    /// This class implements the Front Controller pattern by subscribing conditional events.
    /// When this class is given the execution path (through Process()), it runs through each
    /// conditional in the order it was subscribed.  If the conditional meets the criteria it
    /// defines, its Action is executed.
    /// </summary>
    public class FrontController : List<Conditional>
    {

        /// <summary>
        /// Creates a Conditional based on the input parameters and adds
        /// it to the list.
        /// </summary>
        /// <param name="query">Delegate to test the criteria</param>
        /// <param name="action">Delegate to execute the desired action when the 
        /// conditional is met</param>
        public void Add( Query query, Action action )
        {
            Conditional c = new Conditional( query, action );
            this.Add( c );
        }

        /// <summary>
        /// Test subscribed conditionals and execute the first one that is met.
        /// </summary>
        /// <param name="url">URL to pass to the subscribed delegates</param>
        /// <returns>the result returned from the executed delegate.  if nothing 
        /// is executed, returns null.</returns>
        public ActionResult Process( Uri url )
        {
            foreach ( Conditional action in this )
            {
                if ( action.DoesMatch( url ) )
                {
                    return action.Execute( url );
                }
            }
            return null;
        }


    }

    /// <summary>
    /// delegate to test the given URL to see if it should be processed.
    /// </summary>
    /// <returns>true to process</returns>
    public delegate bool Query( Uri requestedUrl );

    /// <summary>
    /// delegate to execute functionality based on the given URL
    /// </summary>
    /// <returns>results of the method</returns>
    public delegate ActionResult Action( Uri requestedUrl );

    /// <summary>
    /// Pair of delegates that matches the functionality in an 'if' statement.
    /// The Query is the delegate to test the arguments to see if the Action 
    /// delegate should be executed.
    /// </summary>
    public class Conditional
    {
        /// <summary>
        /// delegate to test the input parameter to see if it matches the criteria
        /// </summary>
        public Query DoesMatch;
        /// <summary>
        /// delegate to execute logic based on the input parameter when the DoesMatch
        /// delegate is satisfied.
        /// </summary>
        public Action Execute;

        /// <summary>
        /// helper constructor.  intializes the members to the parameter values.
        /// </summary>
        public Conditional( Query doesMatch, Action action )
        {
            this.DoesMatch = doesMatch;
            this.Execute = action;
        }
    }

    /// <summary>
    /// Container for the results of a Conditional's execute method.
    /// </summary>
    public class ActionResult
    {
        /// <summary>
        /// true if the ContentPresenter should continue and display the requested resource
        /// </summary>
        public bool Continue = true;
        /// <summary>
        /// the filename of the user control to use as a view for the request resource
        /// </summary>
        public string ControlName;
        /// <summary>
        /// the object that will be passed to the view to use as its primary data source
        /// </summary>
        public object DataSource;
        /// <summary>
        /// the object that will be passed to the view to be used by the master page for
        /// its data source
        /// </summary>
        public object MasterDataSource;
        /// <summary>
        /// message to be displayed to the user if the request cannot be satisfied.
        /// </summary>
        public string ErrorMessage;
    }


}
